#include "LecteurPhraseAvecTable.h"

#include <stdlib.h>
#include <iostream>
using namespace std;

////////////////////////////////////////////////////////////////////////////////

LecteurPhraseAvecTable::LecteurPhraseAvecTable(string nomFich) :
ls(nomFich), ts() {
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::analyse() {
    try {
        nbErreurs = 0;
        programme();
        cout << "Syntaxe correcte." << endl;
    }    catch (int nb) {
        cout << "Syntaxe incorrecte: " << nb << " erreurs" << endl;
    }
}


////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::programme() {
    // <programme> ::= debut <seqInst> fin FIN_FICHIER

    sauterSymCour("debut");
    seqInst();
    while (ls.getSymCour() != "fin" && ls.getSymCour() != "<FINDEFICHIER>") {
        seqInst();
    }
    sauterSymCour("fin");
    try {
        testerSymCour("<FINDEFICHIER>");
    } catch (string symb) {
        cout << endl << "-------- Erreur ligne " << ls.getLigne()
                << " - Colonne " << ls.getColonne() << endl << "   Attendu : "
                << symb << endl << "   Trouve  : " << ls.getSymCour() << endl
                << endl;
    }
    try {
        if (nbErreurs > 0) {
            throw nbErreurs;
        }
    } catch (int nb) {
        throw nb;
    }
}
////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::seqInst() {
    // <seqIns> ::= <inst> ; { <inst> ; }
    // <seqInst> ::= <inst> ; { <inst> ; }

    do {
        if (ls.getSymCour() == "pour") {
            inst();
        } else {
            inst();
            sauterSymCour(";");
        }
    } while (ls.getSymCour() == "<VARIABLE>" || ls.getSymCour() == "repeter"
            || ls.getSymCour() == "tantque" || ls.getSymCour() == "si"
            || ls.getSymCour() == "lire" || ls.getSymCour() == "ecrire"
            || ls.getSymCour() == "pour");
    // tant que le symbole courant est un debut possible d'instruction...
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::inst() {
    // <inst> ::= <affectation>

    if (ls.getSymCour() == "si") {
        instSi();
    } else if (ls.getSymCour() == "tantque") {
        instTq();
    } else if (ls.getSymCour() == "repeter") {
        instRepeter();
    } else if (ls.getSymCour() == "lire") {
        instlire();
    } else if (ls.getSymCour() == "ecrire") {
        instecrire();
    } else if (ls.getSymCour() == "pour") {
        instPour();
    } else if (ls.getSymCour() == "<VARIABLE>") {
        affectation();
    } else {
        erreur("<inst>");
    }
}

void LecteurPhraseAvecTable::instSi() {
    if (ls.getSymCour() == "si") {
        ls.suivant();
        sauterSymCour("(");
        expBool();
        sauterSymCour(")");
        seqInst();
        while (ls.getSymCour() == "sinonsi") {
            ls.suivant();
            sauterSymCour("(");
            expBool();
            sauterSymCour(")");
            seqInst();
        }
        if (ls.getSymCour() == "sinon") {
            ls.suivant();
            seqInst();
        }
        sauterSymCour("finsi");

    } else erreur("<instSi>");
}

void LecteurPhraseAvecTable::instTq() {
    if (ls.getSymCour() == "tantque") {
        ls.suivant();
        sauterSymCour("(");
        expBool();
        sauterSymCour(")");
        seqInst();
        sauterSymCour("fintantque");
    } else erreur("<instTq>");
}
////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::instPour() {// pour ( <affectation>;<expBool>;<affectation> ){<seqInst>}
    if (ls.getSymCour() == "pour") {
        ls.suivant();
        sauterSymCour("(");
        affectation();
        sauterSymCour(";");
        expBool();
        sauterSymCour(";");
        affectation();
        sauterSymCour(")");
        sauterSymCour("{");
        seqInst();
        sauterSymCour("}");

    } else erreur("<instPour>");
}
////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::instRepeter() {
    if (ls.getSymCour() == "repeter") {
        ls.suivant();
        seqInst();
        if (ls.getSymCour() == "jusqua") {
            ls.suivant();
            sauterSymCour(")");
            expBool();
            sauterSymCour(")");
        }

    }
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::affectation() {
    // <affectation> ::= <variable> = <expression>

    //sauterSymCour("<VARIABLE>");
    try {
        testerSymCour("<VARIABLE>");
    } catch (string ch) {
        cout << endl << "-------- Erreur ligne " << ls.getLigne()
                << " - Colonne " << ls.getColonne() << endl << "   Attendu : "
                << ch << endl << "   Trouve  : " << ls.getSymCour() << endl
                << endl;
    }
    ts.chercheAjoute(ls.getSymCour());
    ls.suivant();
    sauterSymCour("=");
    expression();
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::expression() {
    // <expression> ::= <facteur> { <opBinaire> <facteur> }
    // <expression> ::= <terme> { <opBinaire> <terme> }
    terme();
    while (ls.getSymCour() == "+" || ls.getSymCour() == "-") {
        opAdd();
        terme();
    }
}
////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::expBool() {
    // <expBool> ::= <relation> { <opOu> <relation> }
    termeBool();
    while (ls.getSymCour() == "ou") {
        opOu();
        termeBool();
    }
}
////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::facteur() {
    // <facteur> ::= <entier>  |  <variable>  |  <opUnaire> <exBool> |  ( <expBool> )
    if (ls.getSymCour() == "<VARIABLE>" || ls.getSymCour() == "<ENTIER>") {
        ts.chercheAjoute(ls.getSymCour());
        ls.suivant();
    } else if (ls.getSymCour() == "-" || ls.getSymCour() == "non") {
        opUnaire();
        expBool();
    } else if (ls.getSymCour() == "(") {
        ls.suivant();
        expBool();
        sauterSymCour(")");
    } else
        erreur("<facteur>");
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::opAdd() { //  <opAdd> ::= +|- /

    if (ls.getSymCour() == "+" || ls.getSymCour() == "-")
        ls.suivant();
    else
        erreur("<opAdd>");
}
////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::opMult() { //  <opAdd> ::= +|- /

    if (ls.getSymCour() == "*" || ls.getSymCour() == "/")
        ls.suivant();
    else
        erreur("<opMult>");
}


////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::opEt() {//  <opBool> ::= et|ou /

    if (ls.getSymCour() == "et")
        ls.suivant();
    else
        erreur("<opEt>");
}

void LecteurPhraseAvecTable::opOu() {//  <opBool> ::= et|ou /

    if (ls.getSymCour() == "ou")
        ls.suivant();
    else
        erreur("<opOu>");
}

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::relation() {
    expression();
    while (ls.getSymCour() == "==" || ls.getSymCour() == "!=" || ls.getSymCour() == "<" || ls.getSymCour() == ">" || ls.getSymCour() == "<=" || ls.getSymCour() == ">="
            || ls.getSymCour() == "et") {
        if (ls.getSymCour() == "et") {
            opEt();
            expBool();
        } else {
            opRel();
            expression();
        }
    }
}
////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::opRel() {
    //  <opBool> ::= ==|!=|>|<=|>=|< /

    if (ls.getSymCour() == "==" || ls.getSymCour() == "!=" || ls.getSymCour() == "<" || ls.getSymCour() == ">" || ls.getSymCour() == "<=" || ls.getSymCour() == ">=")
        ls.suivant();
    else
        erreur("<opRel>");
}
////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::opUnaire() {
    //  <opUnaire> ::= -|non
    if (ls.getSymCour() == "-" || ls.getSymCour() == "non")
        ls.suivant();
    else
        erreur("<opUnaire>");
}
////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::terme() //<terme> ::= <facteur> {<opAdd> <terme>}
{
    facteur();
    while (ls.getSymCour() == "*" || ls.getSymCour() == "/") {
        opMult();
        facteur();
    }
}
////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::termeBool() {// <facteur>{<opEt><relation>}
    relation();
    while (ls.getSymCour() == "et") {
        opEt();
        relation();
    }
}
////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::instlire() {
    if (ls.getSymCour() == "lire") {
        ls.suivant();
        sauterSymCour("(");
        try {
            testerSymCour("<VARIABLE>");
        }        catch (string ch) {
            cout << endl << "-------- Erreur ligne " << ls.getLigne()
                    << " - Colonne " << ls.getColonne() << endl << "   Attendu : "
                    << ch << endl << "   Trouve  : " << ls.getSymCour() << endl
                    << endl;
        }
        ts.chercheAjoute(ls.getSymCour());
        ls.suivant();
        sauterSymCour(")");
    } else erreur("<instlire>");
}

void LecteurPhraseAvecTable::instecrire() {

    if (ls.getSymCour() == "ecrire") {
        ls.suivant();
        sauterSymCour("(");
        if (ls.getSymCour() == "<CHAINE>" || ls.getSymCour() == "<VARIABLE>") {
            ls.suivant();
        } else {
            expression();
        }
        sauterSymCour(")");
    } else
        erreur("<instecrire>");
}
////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::testerSymCour(string ch) {
    try {
        if (ls.getSymCour() != ch) {
            throw ch; //  on leve une exception
        }
    } catch (string symb) {
        nbErreurs = nbErreurs + 1;
        throw symb;
    }
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::sauterSymCour(string ch) {
    try {
        testerSymCour(ch);
        ls.suivant();
    } catch (string symb) {
        cout << endl << "-------- Erreur ligne " << ls.getLigne()
                << " - Colonne " << ls.getColonne() << endl << "   Attendu : "
                << ch << endl << "   Trouve  : " << ls.getSymCour() << endl
                << endl;
    }
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::erreur(string mess) {

    try {
        throw mess;
    } catch (string message) {
        nbErreurs = nbErreurs + 1;
        cout << endl << "-------- Erreur ligne " << ls.getLigne() << " - Colonne "
                << ls.getColonne() << endl << "   Attendu : " << message << endl
                << "   Trouve  : " << ls.getSymCour() << endl << endl;
        ls.suivant();
    } // plus tard, on levera une exception
}
